  /*********************************************************************
   *                                                                   *
   *    Mortality rates Based on chapter 7 of the DHS report           *
   *                                                                   *
   *   Guidelines of October 31,  1994 - Version 5.0.1 of 09/22/95     *
   *                                                                   *
   ********************************************************************/
/*
    MODIFIED SSA 22+ Aug 2011 - making more efficient
             SSA 28 DEC  2011 - added bootci option to PSU parameter
             SSA 05 JAN  2012 - fixed date macro (it was a cosmetic error / added index explanation in log file.
             SSA 27 MAR  2012 - added output files - new parameters , _count_ = output file extention, outlib = output library.
             SSA DT 05 APR 2012 - changed name version !
			 DT 23 APR 2012 - changed default SURVEY_DATE_FLAG
  Version 1.0
  INPUTS
  DATA:   Data set name (and library location). Each record should represent one birth.
  PSU:  Primary Sampling Unit (PSU) ID if the sample was a multistage cluster sample. PSU = V021 in the DHS.
        optional: If there is no PSU, a bootstrap-like option is available
                  the syntax is: PSU = bootci ###
                  - where ### is the number of bootstraps you want (they are actually pseudo-PSU's)

  BYVAR:  Categorical variable describing sub-populations of interest. The DHS commonly presents child mortality
      statistics by region (V024) and urban/rural residence (V025). If two or more variables describe your
      subpopulations (e.g. urban/rural populations within regions), then generate a new single variable to
      uniquely identify the smallest units in the sub-population. To ensure correct standard errors, do not
      delete any records (categorize all observations).
  DOB:  Child�s date of birth (DOB). In the DHS, variable B3 represents DOB in century-month format. Depending
      on the format of DOB in your dataset, you may specify more than one variable:
      � CMC (century-month format): [variable]
      � SAS date: [variable]
      � mm yyyy: [month variable] [year variable]
      � dd mm yyyy: [day variable] [month variable] [year variable]
  AOD:  Age of death (AOD) in months. This variable can be formatted as an integer or as a fraction. In the DHS,
      B7 represents age of death in months as an integer.
  FACTIONAL: This statement effects how the age of death value is used in the survival analysis. If AOD is an integer
      and DOB is in CMC format (as is the case for DHS datasets), you can add a partial month, or random day, to
      AOD and DOB using the FRACTIONAL statement thereby improving estimates of the probability of death within each
      age category. If your dataset already has day, month, and year information for AOD and DOB, then age of death
      should be a fraction (e.g. 14.8 months). Specify one of the following values in the FRACTIONAL statement:
      � 0: Use the AOD variable as it is (an integer or fraction)
      � 1: add a uniform random partial month to AOD between 0 and 1 (if AOD is an integer)
      � 2: add a uniform random partial month to AOD between -0.5 and 0.5 (if AOD is an integer)
  WEIGHT: Sample weight for each observation. In the DHS, V005 is the sample weight multiplied by 1,000,000 so the value
      is stored as an integer.  You may specify either V005 (integer) or the actual sample weight (fraction) here.
      If blank a constant weight of 1 will be used (unweighted).
  SURVEY_DATE:  Refers to the date of the survey with the mother. SURVEY_DATE, SURVEY_DATE_FLAG, and YEARS are used together
      to determine which records from the birth history are used in the child mortality calculation. Depending on the
      format of your dataset, you may specify more than one variable here. Alternatively, you may specify a single date
      that marks the end of the birth history window for all women.
      If you specify SURVEY_DATE_FLAG = 1 or 0, and you have collected the survey date for each mother, then enter the
      following variables:
      � CMC (century-month format): [variable]
      � SAS date: [variable]
      � mm yyyy: [month var] [year var]
      � dd mm yyyy: [day var] [month var] [year var]
      If you�d like to specify the final date in the birth history window, enter that date here using the format
      described in SURVEY_DATE_FLAG.
  SURVEY_DATE_FLAG: Birth histories from the last 5 or 10 years are used to calculate child mortality. You can specify when
      that birth history window ends:
      � 0: Window ends at the date of interview of the mother
      � 1: Window ends at the date of first interview in the sample
      � If you specified a date in SURVEY_DATE, then enter the format of that date here. Examples:
        o MMDDYY8.
        o DDMMYY10.
        o DATE10.
  YEARS:  The window of 5 or 10 years of birth histories to be included in the calculation. The user may only specify 5 or 10 years.
  AAI:  A binary variable that indicates whether the child was alive at the time of interview. 0 indicates the child was dead, and
      1 indicates the child was alive. In the DHS, this information is stored in variable B5.

  OUTLIB : output library for DHS_U5M.sas7bdat

*/

%MACRO DHS_U5M(DATA= _LAST_,
                     PSU = ,
                     BYVAR = ,
                     DOB = b3,
                     AOD = B7,
                     FRACTIONAL = 0,
                     WEIGHT =,
                     SURVEY_DATE = V008 ,
                     SURVEY_DATE_FLAG = 0,
                     YEARS = 5,
                     AAI=B5,
                     _count_ =,
                     outlib =
                     )
;

  %local title1 title2 title3 title4 title5 title6 title7 title8;
  %let title1 = Processing &data with: cluster = &PSU, DOB = &DOB, Age at death = &AOD;
  %let title2 =  alive at interview = &AAI, years = &years;

  %if &survey_date_flag = 0 %then %let title3 = survey_date = &survey_date - variable by individual;
  %else %if &survey_date_flag = 1 %then %let title3 = survey date = &survey_date - using minimum date, constant for all (see log);
  %else %let title3 = survey date = &survey_date - constant for all, formatted by &survey_date_flag;;

  %if       &fractional = 1 %then %let title4 = Adding uniform random partial months [0,1) to dates and ages;
  %else %if &fractional = 2 %then %let title4 = Adding plus or minus uniform random partial months [-0.5,0.5) to dates and ages;
  %let title5 = Processing &years years before, until survey date;
  %logline;
  %put Version = 0.17;
  %put &title1;  %put &title2;  %put &title3;  %put &title4;  %put &title5;

  %local note_option;
  %let note_option = %sysfunc(getoption(NOTES));
  options nonotes;
  title;
  footnote;
  %if %length(&_count_) > 0 %then
  %do;
    %if %length(&outlib) = 0 %then %let outlib = work;
    %else %if (%sysfunc(libref(sashelp))) %then
    %do;
      %put MACRONOTE: libref &outlib not assigned - using WORK;
      %let outlib = work;
    %end;
   %end;

  %let title8 = Output: &outlib..MORT_DHS_DGHE_&_count_;

  %check_ds_vars(&data,, &byvar &AAI &AOD ,1);

  %if %symexist(debug) = 1 %then options notes;

  %if %length(&file_errmsg) > 0 %then %goto mainexit;
  %if %length(&var_nonnum_errmsg) > 0 %then %goto mainexit;

  /* we open up a 'new' work folder for our stuff */
  %local workdir worklibdir dexist;
  %let workdir = %sysfunc(getoption(WORK));;
  filename mywork "&workdir\__U5__";

  %let dexist = %sysfunc(dopen(mywork));
  %if &dexist > 0 %then
  %do;
    %let dexist = %sysfunc(dclose(&dexist));
    %let worklibdir = &workdir\__U5__;
  %end;
  %else %let worklibdir = %sysfunc(dcreate(__U5__,&workdir));

  %if #&worklibdir = # %then
  %do;
    %let worklibdir = &workdir;
    %let dont_delete = dont_delete;
  %end;

  libname __U5__ "&worklibdir";

  %local dont_delete;
  %let dont_delete = okay_to_delete;

  %if #&years ^= #5 %then %if #&years ^= #10 %then
  %do;
    %put;%put ERROR: Years = &years - Years must equal 5 or 10;%put;
    %goto mainexit;
  %end;

  %let inlib=%scan(&data,1,.);
  %let select = %scan(&data,2,.);
  %if #&select=# %then
  %do;
    %let select = &inlib;
    %let inlib = work;
  %end;
  %local NCLUSTER;
  proc copy in = &inlib out=__u5__;
    select &select;
    run;
  quit;
  %let data = __U5__.&select;
  %if #&weight = # %then
  %do;
    %let weight = ___weight;
    data &data;
      set &data;
        ___weight = 1;
    run;
    %let title6 = weight variable = unweighted (constant 1);
  %end;
  %else
  %do;
     %check_ds_vars(&data,,&weight,1);
     %if %length(&var_nonnum_errmsg) > 0 %then %goto mainexit;
     %let title6 = weight variable = &weight;
     %put title6;
  %end;
  %local bootstrap_number boot_percent do_bootstrap;
  %if %index(&psu,bootci) > 0 %then
  %do;
    %let bootstrap_number = %scan(&PSU,2);
    %let NCLUSTER = &bootstrap_number;
    %if %sysfunc(compress(#&bootstrap_number,,d))=# AND #&bootstrap_number > # %then
    %do;
      data &data;
      set &data;
        ___PSU_Contrived = int(ranuni(87468723) * &bootstrap_number) + 1;
      run;
      %let PSU = ___PSU_Contrived;
      %let title7 = Using bootstrap &bootstrap_number random clusters for sampling errors;
    %end;
    %else
    %do;
      %put MACRONOTE: Bootstrap parameter error;
      %goto mainexit;
    %end;
  %end;
  %else
  %do;
      %check_ds_vars(&data,,&PSU,1);
      %if %length(&var_nonnum_errmsg) > 0 %then %goto mainexit;
      %let title7 = Using PSU = &PSU for sampling errors;
      %put &title7;
  %end;
  %logline;
  %local minsurveydate;%let minsurveydate=;
  %window STATUS Rows=16 columns=120
    #2 @5 title1
    #3 @5 title2
    #4 @5 title3
    #5 @5 title4
    #6 @5 title5
    #7 @5 title6
    #8 @5 title7
    #10 @5 ACTION
  ;;
  %let ACTION = Calculating age categories at death;
  %display status noinput;

  %check_create_date_vars(data=&data,invar=&dob,return_var=___dob,fractional=&fractional);

  %if &survey_date_flag=0 OR &survey_date_flag = 1 %then
  %do;
    %*%check_ds_vars(&data,,&survey_date,1);
    %if %length(&var_nonnum_errmsg) > 0 %then %goto mainexit;
    %check_create_date_vars(data=&data,invar=&SURVEY_DATE,return_var=___SURVEY_DATE,fractional=&fractional);
    %if &survey_date_flag = 1 %then
    %do;
      proc means data=&data noprint;
        var ___survey_date;
        output out=__U5__.mindate min=minsurveydate max = maxsurveydate mean=meansurveydate;
      run;
      data _null_;
      set __U5__.mindate;
        call symput("minsurveydate", minsurveydate);
        format minsurveydate date9.;
        format outstr $1024.;
        years = int(minsurveydate / 12);
        months = minsurveydate - (years * 12);
        years = years + 1900;
        realdate = mdy(months,1,years);
        outstr = "*** Using " || put(realdate,date9.) || " as basis date";
        put outstr;
        format diff_mean diff_max 5.2;
        diff_mean = meansurveydate - minsurveydate;
        diff_max = maxsurveydate - minsurveydate;
        outstr = "*** Which is " || put(diff_mean,5.2) || " months before the mean date";
        put outstr;
        outstr = "*** and " || put(diff_max,5.2) || " months before the maximum date.";
        put outstr;
      run;
      data &data;
      set &data;
        ___survey_date = &minsurveydate;
      run;
    %end;
  %end;
  %else
  %do;
    %if %sysfunc(index(&survey_date,SAS)) > 0 %then
      %check_create_date_vars(data=&data,invar= SAS &SURVEY_DATE,return_var=___SURVEY_DATE,fractional=&fractional);
     %else
     %do;
      %local date_format_error;
      data &data;
      set &data;
        ___survey_date___ = input("&survey_date",&survey_date_flag);
        if _error_ = 1 then
        do;
          call symput("date_format_error",1);
          put "ERROR: Survey date format error - &survey_date not correct for survey_date_flag = &survey_date_flag";
          stop;
        end;
      run;
      %if &date_format_error = 1 %then %goto mainexit;
      %put "Using &survey_date as constant survey date";
      %check_create_date_vars(data=&data,invar= SAS ___SURVEY_DATE___,return_var=___SURVEY_DATE,fractional=&fractional);

    %end;
  %end;
  %if &fractional = 1 %then
  %do;
    data &data;
    set &data;
      &AOD = &AOD + (ranuni(11111));
    run;
  %end;
  %else %if &fractional = 2 %then
  %do;
    data &data;
    set &data;
      &AOD = &AOD + (0.5 - ranuni(11111));
    run;
  %end;

  /* gets gross number of children per bygroup*/
  data gross_count;
  set &data;

    %IF &BYVAR=  %THEN %LET TEMP_BY = 99999;
    %ELSE %LET TEMP_BY = &BYVAR;
    W_BYVAR = &TEMP_BY;
    if ___DOB < = (___survey_date - &years * 12 );
    keep w_byvar ___dob;
  run;
  proc means data= gross_count noprint;
    class w_byvar;
    var ___dob;
    output out = __u5__.gross_count(where=(NOT missing(w_byvar))) N=count_per_bygroup;
  run;
  %logline;
  %put Calculating deaths;

  /*  Assigns deaths to age groups and 5 year periods */

  Data __U5__.iter1(index=(&PSU)) __U5__.iter2(index=(&PSU));
  Set &DATA;
    array agegrp {10} (0 1 3 6 12 24 36 48 60 0);  /* Creates age cohorts */
    array limits {10};  /* Creates analysis periods */


    period     = 60;  /* Sets length of anlysis periods in months (must be <= 60 months) */
    limits[1] = ___survey_date - period;  /* Establishes boundries for the analysis periods */
    upplim = ___survey_date - 1;  /* Sets upper limit for analysis */
    perborn = Int((___survey_date - 1 - ___DOB)/period) + 1;


    Do i = 2 To 10;
      limits[i] = limits[i-1] - period;
    End;
    lowlim = limits10;  /* Sets lower limit for analysis */

    /* Selects only those children who were born in the period */
    /* of analysis and who had died prior to the interview     */

    If lowlim <= ___DOB <= upplim AND &AAI = 0;

    months = &AOD;  /* Imputed age at death*/

    agedth = .;  /* Creates variable agedth which will be age group in which the child died */

    /* Assigns children who were under 60 months when they died to a death age group */
    Do i = 1 To 8;
      If (agegrp[i] <= months < agegrp[i+1]) Then
      Do;
        agedth = i;
        i = 10;
      End;
    End;

    If agedth ^= .;  /* Excludes children who died after 5 years of age */

    agei   = ___DOB + agegrp[agedth];  /* lower limit of age group of death */
    nxtage = ___DOB + agegrp[agedth + 1];  /* upper limit of age group of death */

    limlow = limits(perborn);  /* Lower limit of the birth period */

    If perborn > 1 Then limupp = limits(perborn-1);  /* Upper limit of the birth period */
    Else limupp = upplim + 1;

    n = 1;
    iter = 0;

    /* If the child's age group of death spans one period, */
    /* the death is counted once in that period            */
    If limlow <= ___DOB & nxtage < limupp Then
    Do;
      iter = 1;
      n = 1;
    End;

    /* If the child's age group at death spans two periods,    */
    /* the death is counted half in each period                 */
    If agei < limupp <= nxtage Then
    Do;
      iter = 2;
      n = 0.5;
      If perborn = 1 Then
      Do;
        iter = 1;
        n = 1;
      End;
    End;

    /* If the child's age group at death spans period i + 1, but */
    /* the child was born is period i, the death is counted in period i+1   */
    If ___DOB < limupp <= agei Then
    Do;
      perborn = perborn - 1;
      iter = 1;
      n = 1;
    End;

    colper  = perborn;

    ADJ_WGT= n * &WEIGHT; /* Creates the weight that will be used for the data */
    IF 1 <= COLPER <= 5;  /* analysis period between 1 and 5 */
    IF ITER ^= 0 THEN OUTPUT __U5__.ITER1;
    IF ITER =  2 THEN
    do;
      colper = perborn - 1;
      OUTPUT __U5__.ITER2;
    end;
  RUN;
  /* The following section crosstabs the first iteration */

  %clean_log(ON);
  Proc Freq DATA=__U5__.ITER1 NOPRINT;
    Tables agedth * colper/NoPercent NoRow NoCol Out=__U5__.deathsH(index=(sortme=(&PSU AGEDTH COLPER)));
    Weight ADJ_WGT;
    BY &PSU;
  Run;

  /* The following section crosstabs the second iteration */
  Proc Freq DATA=__U5__.ITER2 noprint;
    Tables agedth*colper/NoPercent NoRow NoCol Out=__U5__.deathsL(index=(sortme=(&PSU AGEDTH COLPER)));
    Weight ADJ_WGT;
    BY &PSU;
  Run;

  Data __U5__.Deaths(index=(&psu));
  Merge __U5__.deathsH(Rename=(count=higdth)) __U5__.deathsL(Rename=(count=lowdth));
  By &PSU agedth colper;
    nbdths    = Sum(higdth,lowdth);
    IF &YEARS=5  THEN
    DO;
      IF COLPER=1;
    END;           /* RESTRICT CALCULATION */
    IF &YEARS=10 THEN
    DO;
      IF COLPER IN (1,2);
    END;    /* TO 5 OR 10 YEARS BEFORE SURVEY */
  Run;
 /*  data sasuser.mdg_deathsh;set __u5__.deathsh;run;data sasuser.mdg_deathsl;set __u5__.deathsl;run;endsas;*/

  Proc Freq DATA=__U5__.DEATHS NOPRINT;
    Tables agedth * colper/NoPercent NoRow NoCol Out=__U5__.deaths(index=(sortme=( &psu AGEDTH COLPER)));
    Weight nbdths;
    BY &PSU;
  Run;

  %IF &YEARS=10 %THEN
  %DO;
    PROC MEANS DATA=__U5__.DEATHS SUM NOPRINT;
      VAR COUNT;
      class &PSU AGEDTH;
      OUTPUT OUT=__U5__.DEATHS SUM=;
    RUN;
    DATA __U5__.DEATHS(index=(sortme=( &psu AGEDTH COLPER)));
      SET __U5__.DEATHS(where=(nmiss(&PSU, AGEDTH) = 0) DROP=_TYPE_ _FREQ_);
      COLPER=10;
    RUN;
  %END;

  %clean_log;
  /****************************************************************************
  *  Births: Temporary data set that holds the limits of the period of birth  *
  *          of the child.                                                    *
  *  ExposH: Contains the data used in the first iteration for the age cohort *
  *          being analysed.                                                  *
  *  ExposL: Contains the data used in the second iteration for the age cohort*
  *          being analysed.                                                  *
  *  Expos_c_: Exposure for the age cohort _c_. _c_ varies from 1 to 8.       *
  *  Exposure: Exposure for all the age cohorts. A conatenation of Expos1 to  *
  *            Expos8.                                                        *
  *                                                                           *
  *       Exposure of children in each period of analysis.                    *
  *       The Exposure is calculated in number of children Exposed in each    *
  *       age cohort for all the periods of analysis.                         *
  *       The computation of the Exposure is done in the same way as for the  *
  *       number of deaths, except for the last period where we take half of  *
  *       the Exposure whether the child died or not.                         *
  ***************************************************************************/

  %put Calculating births;

  Data __U5__.births;
  Set &DATA;
    array agegrp{10} (0 1 3 6 12 24 36 48 60 0);             /* Creates age groups */
    array limits{10};                                        /* Creates analysis periods */

    /* Sets length of analysis periods in months (must be <= 60 months) */
    period     = 60;

    limits[1] = ___survey_date - period;  /* Establishes boundries for the analysis periods */
    upplim = ___survey_date - 1;  /* Sets upper limit for analysis */
    perborn = Int((___survey_date - 1 - ___DOB)/period) + 1;
       /* Current age or age at death of the child. */
    If &AAI = 0 Then months = &AOD;
    Else months = (___survey_date - ___DOB);

    Do i = 2 To 10;
      limits[i] = limits[i - 1] - period;
    End;

    lowlim = limits10;  /* Sets lower limit for analysis */

    /* Selects only those children who were born in the period of analysis */
    If lowlim <= ___DOB <= upplim;



    /* Establishes the period of birth; ...+1 is to */
    /* be consistent with the analysis periods      */
    *see above perborn;

    TMPWGT = 1;   /**** temporary weight used in calculating unweighted numbers of cases ****/

    %IF &BYVAR=  %THEN %LET TEMP_BY = 99999;
    %ELSE %LET TEMP_BY = &BYVAR;
    W_BYVAR = &TEMP_BY;
  run;

  /* The following section tabulates exposure in the different age groups */
  /*  ageexp is equal to the number of the age group being tabulated   */


%MACRO EXPOSURE(VARBY=, WEIGHT2=, OUTDSN=);
  %window STATUS Rows=18 columns=120
    #2 @5 title1
    #3 @5 title2
    #4 @5 title3
    #5 @5 title4
    #6 @5 title5
    #7 @5 title6
    #8 @5 title7
    #10 @5 ACTION
    #12 @5 'Age group =' +1 I +6 'by' +1 varby
  ;;
  %let ACTION= Calculating exposure;
  %put Calculating Exposure;
  %DO i = 1 %TO 8;
    %display status noinput;;
    Data __U5__.iter1(index=(&VARBY)) __U5__.iter2(index=(&VARBY));
    Set __U5__.Births;
      array agegrp[10] agegrp1 - agegrp10;
      array limits[10] limits1 - limits10;

      ageexp = &i; /* Sets the number of the current age group */
      IF PERBORN > 0; /* who wouldn't be born? */

      /* Sets the lower bound for the period in which the child was born */
      limlow = limits[perborn];

      /* Sets the upper bound for the period in which the child was born */
      If perborn > 1 Then limupp = limits[perborn - 1];
      Else limupp = upplim + 1; /* survey month */

      /* Sets the lower bound for the child's age group */
      agei   = ___DOB + agegrp[ageexp];
      nxtage = ___DOB + agegrp[ageexp + 1];  /* Sets the upper bound for the child's age group */

      /* Selects children exposed for at least part of the age */
      /* group; i.e. children who enter the age group          */
      If agegrp[ageexp] <= months;

      iter    = 0;

      /* All exposure occurs in period following birth period */
      If limupp <= agei Then
      Do;
        perborn = perborn - 1;
        iter = 1;
        n = 1;
        If perborn > 0 Then limlow = limits[perborn];
        If perborn > 1 Then limupp = limits[perborn - 1];
        Else limupp = upplim + 1;
      End;
      /* All exposure occurs in birth period */
      If nxtage < limupp Then
      Do;
        iter = 1;
        n = 1;
      End;

      /* Exposure occurs in period of birth and following period  */
      /* child is counted as half in both periods                 */
      If agei < limupp <= nxtage Then
      Do;
        iter = 2;
        n    = 0.5;
        If perborn = 1 Then iter = 1;
      End;
      colper = perborn;

      ADJ_WGT = n * &WEIGHT;    /* Creates a weight for the data */

      IF 1 <= COLPER <= 5;
      IF ITER ^= 0 THEN OUTPUT __U5__.ITER1;
      IF ITER =  2 THEN
      do;
        colper = perborn - 1;
        OUTPUT __U5__.ITER2;
      end;
    RUN;
    /* Tabluates the first part of the exposure in */
    /* the age group by period of analysis   */
    Proc Freq DATA=__U5__.ITER1 noprint;
      Tables ageexp * colper/NoPercent NoRow NoCol Out=__U5__.ExposH(index=(sortme=(&VARBY AGEEXP COLPER)));
      Weight &weight2;
      BY &VARBY;
    Run;
    /* Tabulates the second part of the exposure in */
    /* the age group by period of analysis    */

    Proc Freq DATA=__U5__.ITER2 noprint;
      Tables ageexp * colper/NoPercent NoRow NoCol Out=__U5__.ExposL(index=(sortme=(&VARBY AGEEXP COLPER)));
      Weight &weight2;
      BY &VARBY;
    Run;

    Data __U5__.BirthsE(index=(&varby));
    Merge __U5__.ExposH(Rename=(count=higexp))
          __U5__.ExposL(Rename=(count=lowexp))
    ;
    By &VARBY ageexp colper;

      nbchild = Sum(higexp,lowexp);  /* Creates a weight for the data */
      /* Tabulates exposure in the age group by period of analysis */
      /*  and writes results to a file called exposi  */

      IF &YEARS=5  THEN
      DO;
        IF COLPER=1;
      END;  /* RESTRICT CALCULATION */
      IF &YEARS=10 THEN
      DO;
        IF COLPER IN (1,2);
      END;   /* TO 5 OR 10 YEARS BEFORE SURVEY */
    RUN;

    Proc Freq DATA=__U5__.BIRTHSE noprint;
      Tables ageexp * colper/NoPercent NoRow NoCol Out=__U5__.Expos&i(index=(sortme=(&VARBY AGEEXP COLPER)));
      Weight nbchild;
      BY &VARBY;
    Run;

  %END;

  Data __U5__.EXPO_ALL(index=(&VARBY));
  Merge __U5__.Expos1 __U5__.Expos2 __U5__.Expos3
        __U5__.Expos4 __U5__.Expos5 __U5__.Expos6
        __U5__.Expos7 __U5__.Expos8
  ;
  By &VARBY ageexp colper;
  RUN;

  Proc Freq DATA=__U5__.EXPO_ALL NOPRINT;
    Tables ageexp * colper/NoPercent NoRow NoCol Out=&OUTDSN(index=(&VARBY));
    Weight Count;
    BY &VARBY;
    /* Title 'Exposure of children'; */
  Run;



  %IF &YEARS=10 %THEN
  %DO;
    PROC MEANS DATA=&OUTDSN SUM NOPRINT;
    CLASS &VARBY AGEEXP;
      VAR COUNT;
      OUTPUT OUT=&OUTDSN SUM=;
    RUN;

    DATA &OUTDSN(index=(&varby));
    SET &OUTDSN(DROP=_TYPE_ _FREQ_ where=(NMISS(&varby,AGEEXP) = 0));
      COLPER=10;
    RUN;
  %END;
%MEND EXPOSURE;

  %clean_log(ON);

  %EXPOSURE(VARBY=&PSU, WEIGHT2=adj_wgt, OUTDSN=__U5__.exposure);

  PROC SORT DATA=&DATA OUT=__U5__.CLUSTER NODUPKEY;
    BY &PSU;
  RUN;

  DATA __U5__.CLUSTER(index=(&PSU));
  SET __U5__.CLUSTER;
    %IF &BYVAR=  %THEN %LET TEMP_BY = 99999;
    %ELSE %LET TEMP_BY = &BYVAR;
    W_BYVAR = &TEMP_BY;
    KEEP &PSU W_BYVAR;
  RUN;

  DATA __U5__.EXPOSURE(index=(sortme=( &psu AGEEXP COLPER))index = (W_BYVAR));
  MERGE __U5__.EXPOSURE(IN=IN1) __U5__.CLUSTER(IN=IN2);
  BY &PSU;
    IF IN1;
  RUN;


  /***** Calculating weighted numbers of children exposed to death ****/

  Proc Freq DATA=__U5__.EXPOSURE noprint;
    Tables ageexp * colper/NoPercent NoRow NoCol out=__U5__.national;
     Weight Count;
  Run;

  Data __U5__.national; set __U5__.national; W_BYVAR=.; run;

  Proc Freq DATA=__U5__.EXPOSURE noprint;
    Tables ageexp * colper/NoPercent NoRow NoCol out=__U5__.domains;
    Weight Count;
    by W_BYVAR;
  Run;

  Data __U5__.nwgt(index=(sortme=( W_BYVAR AGEEXP COLPER)));
  set __U5__.national __U5__.domains;
    rename count=nwgt;
    format count 8.0;
  run;

/***** Calculating unweighted numbers of children exposed to death ****/

%EXPOSURE(VARBY=W_BYVAR, WEIGHT2=TMPWGT, OUTDSN=__U5__.UNWGT);

  Proc Freq DATA=__U5__.UNWGT noprint;
    Tables ageexp * colper/NoPercent NoRow NoCol out=__U5__.nationa2;
    Weight Count;
  Run;

  Data __U5__.nationa2; set __U5__.nationa2; W_BYVAR=.; run;

  Proc Freq DATA=__U5__.UNWGT noprint;
    Tables ageexp * colper/NoPercent NoRow NoCol out=__U5__.domains2;
    Weight Count;
    by W_BYVAR;
  Run;

  Data __U5__.unwgt(index=(sortme=( W_BYVAR AGEEXP COLPER)));
  set __U5__.nationa2 __U5__.domains2;
    rename count = unwgt;
    format count 8.0;
  run;

  DATA __U5__.N_ALL;
  MERGE __U5__.NWGT __U5__.UNWGT;
  BY W_BYVAR AGEEXP COLPER;
  RUN;

   /* Calculates probabilities of dying and final mortality rates */
  /** AND renumbering clusters if there are incompleted clusters **/

  Data __U5__.Probf(index=(&PSU));
    Merge __U5__.exposure(Rename=(count=expo  ageexp=ageprb))
          __U5__.deaths  (Rename=(count=death agedth=ageprb))
          end = last
    ;
    By &PSU ageprb colper;

      label AGEPRB ='Age in months probabilities'
          COLPER='Five years periods of analysis'
      ;
    if death = . then death = 0;
  Run;

  %if %length(&_count_) > 0 %then
  %do;/* sum these by ageprb */
    proc means data=__U5__.probf noprint;
    class ageprb;
      var expo death;
      output out = &outlib..counts_&_count_ sum=;
    run;
  %end;

    %let NCLUSTER = ;
    Data __U5__.Probf(index=(&PSU));
    set __U5__.Probf end = last;
    by &PSU;
      RETAIN RENUMBER 0;
        IF FIRST.&PSU THEN RENUMBER = RENUMBER + 1;
      if last then CALL SYMPUT('NCLUSTER', put(RENUMBER,z4.));   /* total number of clusters */
     run;


  %if %symexist(debug) = 0 %then
  %do;
    PROC DATASETS LIBRARY=__U5__ NOLIST;
      SAVE &select PROBF N_ALL BIRTHS UNWGT NWGT gross_count/ MT=DATA ;
    RUN;
    QUIT;
  %end;
  /** Computing the mortality rates using JKK1 **/
  %clean_log();

  %put Calculating error;
  %window STATUS Rows=18 columns=120
    #2 @5 title1
    #3 @5 title2
    #4 @5 title3
    #5 @5 title4
    #6 @5 title5
    #7 @5 title6
    #8 @5 title7
    #10 @5 ACTION
    #12 @5 'Cluster' +1 J +6 'of' +1 ncluster
  ;;
  %let ACTION = Calculating errors;

  %DO j=0 %TO &NCLUSTER;  /* when j=0, no deletion occurs */
    %display status noinput;
    DATA __U5__.TEMP;
    SET __U5__.PROBF;
      IF RENUMBER=&j THEN
      do; /* deletes one cluster at a time */
        %if %eval(&j > 0) %then
        %do;
          call symput('ran', W_BYVAR);
        %end;
        %else %let ran=0;
        DELETE;
      end;
    RUN;

    PROC SUMMARY DATA=__U5__.TEMP NOPRINT;
      VAR EXPO DEATH;
      CLASS W_BYVAR AGEPRB COLPER /missing;
      OUTPUT OUT=__U5__._TEMP1(DROP=_TYPE_ _FREQ_ where=(AGEPRB ^= . AND COLPER ^= .)) SUM= ;
    RUN;


    /* The sort of Prob is used to have the  */
    /* different age cohorts listed sequentially */

    Data __U5__._TEMP2(index = (COLPER));
    SET __U5__._TEMP1;
      probs = death*1000000/expo; /* 1000000 is used to keep the number of decimals */

      /* Mortrate indicates each mortality rate e.g. 1 = neonatal, */
      /* 3 = infant, 4 = child, and is set to the last age group   */
      /* for each rate                                             */
      mortrate = 99;
      If ageprb = 1 Then mortrate = 1;
      If ageprb = 4 Then mortrate = 3;
      If ageprb = 8 Then mortrate = 4;

      /* First step in calculating neonatal mortality; nm is the */
      /* probability of surviving the first month of life        */
      If ageprb = 1 Then
      Do;
        probdc = (1000000 - probs);
        nm     = probdc;
      End;

      /* First step  in calculating Infant mortality (1q0); infant */
      /* is the probability of surviving the first year of life    */
      l1 = Sum( 0, Lag1(probs)); /* The sum function is used because there */
      l2 = Sum( 0, Lag2(probs));/* might be cases where the previous value */
      l3 = Sum( 0, Lag3(probs));/* is not defined. */

      /* l1, l2, and l3 are used to calculate the probability of surviving */
      /* age groups 3, 2, and 1 respectively                               */
      If ageprb = 4 Then
      Do;
        probdc = (1000000 - probs) *
                  (1000000 -   l1) / 1000000 *
                  (1000000-   l2)  / 1000000 *
                  (1000000-   l3)  / 1000000
        ;
        infant = probdc;
      End;

      /* First step  in calculating child mortality (4q1) */
      l1 = Sum(0, Lag1(probs));
      l2 = Sum(0, Lag2(probs));
      l3 = Sum(0, Lag3(probs));

      /* l1, l2, and l3 are used to calculate the probability of surviving */
      /* age groups 7, 6, and 5 respectively                               */
      If ageprb = 8 Then
            probdc = (1000000 - probs) *
                     (1000000-   l1) / 1000000 *
                     (1000000-   l2) / 1000000 *
                     (1000000-   l3) / 1000000
      ;

      /* Second step in calculating neonatal, infant and child mortality */
      /* Computes probability of death (nqx) from probability of         */
      /* surviving and writes the results to file probs1                 */
      rate = (1000000 - probdc)/1000;
      If (mortrate = 99) Then rate = 0;

      LABEL probs='Probability of death-times 1000000';
    RUN;

    Proc Freq DATA=__U5__._TEMP2 NOPRINT ;
      Tables W_BYVAR*colper*mortrate/NoPercent NoRow NoCol Out=__U5__.probs1;
      Weight rate;

    /*   Title 'Mortality rates per 1000 (1)'; */
    Run;

    Data __U5__._TEMP3;
    Set __U5__._TEMP2;
      mortrate = 99;

      /* Calculates postneonatal mortality (inflated by 1000) */
      /* as infant mortality (1q0) - neonatal mortality       */
      nm       = Sum(0,Lag3(nm));
      /* Mortrate = 2 = postneonatal mortality */
      If ageprb = 4 Then
      Do;
        mortrate = 2;
        rate     = (1000000-probdc) - (1000000-nm);
      End;

      /* Calculates under five mortality (5q0) using the probability    */
      /* of surviving infanthood (0-1) and the probability of surviving */
      /* from exact age 1 to exact age 5 (5q0 is inflated by 1000)      */
      infant   = Sum(0,Lag4(infant));
      /* Mortrate = 5 = under five mortality */
      If ageprb = 8 Then
      Do;
        mortrate = 5;
        rate     = 1000000 - (probdc * infant / 1000000);
      End;
      If mortrate = 99 Then rate = 0;

      /* Calculates postneonatal mortality and under five mortality */
      /* per 1000 and writes the results to file probs2             */
      rate = rate / 1000;
    RUN;

    Proc Freq DATA=__U5__._TEMP3 NOPRINT;
      Tables W_BYVAR * colper * mortrate /NoPercent NoRow NoCol Out=__U5__.probs2;
      Weight rate;
      /*   Title 'Mortality rates per 1000 (2)';   */
    Run;

    Data __U5__._TEMP4;
    Set __U5__.probs1 __U5__.probs2;
      label COLPER='Five years periods of analysis'
      MORTRATE= 'Mortality rate';
    RUN;

    /* Creates the mortality table  which contains */
    /* the mortality rates calculated above        */

    Proc Freq DATA=__U5__._TEMP4 NOPRINT;
      Tables W_BYVAR * colper * mortrate/NoPercent NoRow NoCol OUT=__U5__.TEMP&j;
      Weight Count;
      /* Title 'Mortality rates per 1000'; */
    Run;

    DATA __U5__.TEMP&j;
    SET __U5__.TEMP&j;
      RAN=sum(&RAN,0);
    RUN;

    %IF &j > 0 %THEN
    %DO;
      PROC APPEND BASE = __U5__.TOTAL DATA = __U5__.TEMP&j;
      RUN;

      /* TEMP0 contains the rates for national and for differents levels of by variable */
        PROC DATASETS LIBRARY=__U5__ nolist;
          SAVE &select PROBF TEMP0 TOTAL UNWGT NWGT N_ALL gross_count/MT=DATA;
          RUN;
        QUIT;
    %END;
  %END;

  %put Producing results;
  title;
  /* calculating sampling errors */
  data sasuser.pretotal&do_bootstrap;
  set __u5__.total;
  run;

  DATA __U5__.TOTAL;
  SET __U5__.TOTAL;
    IF W_BYVAR ^= . AND (W_BYVAR - RAN) ^ = 0 THEN DELETE;;;
    RR2 = COUNT**2;  /*  R(i) square  */
  RUN;
  data sasuser.posttotal&do_bootstrap;
  set __u5__.total;
  run;

  PROC SUMMARY DATA=__U5__.TOTAL;
    CLASS  COLPER W_BYVAR MORTRATE;
    VAR RR2 COUNT;
    OUTPUT OUT=__U5__.RESULT1(where=(NMISS(MORTRATE,COLPER,W_BYVAR)= 0)DROP=_TYPE_ _FREQ_)
          SUM=SUM_RR2 SUMCOUNT N(COUNT) = NCLUSTER
    ;
  RUN;

  PROC SUMMARY DATA=__U5__.TOTAL;
    CLASS  COLPER MORTRATE;
    WHERE W_BYVAR=. ;   /* W_BYVAR is missing for replicates at the national level */
    VAR RR2 COUNT;
    OUTPUT OUT=__U5__.RESULT2(where=(NMISS(MORTRATE,COLPER) = 0)DROP=_TYPE_ _FREQ_)
          SUM=SUM_RR2 SUMCOUNT N(COUNT)=NCLUSTER
    ;
  RUN;

  DATA __U5__.RESULT;
  SET __U5__.RESULT1 __U5__.RESULT2(in = inresult2);
    if inresult2 then W_BYVAR = .;
  RUN;

  DATA __U5__.TEMP0;
  SET __U5__.TEMP0;
    RENAME COUNT=RATE;
  RUN;

  /**** adding weighted and unweighted numbers of children exposed to deaths ***/

  PROC SORT DATA=__U5__.N_ALL; BY W_BYVAR; RUN;

  PROC MEANS DATA=__U5__.N_ALL NOPRINT; VAR NWGT UNWGT; BY W_BYVAR;
  WHERE AGEEXP=1; OUTPUT OUT=__U5__.MORT1 MIN=N_WGT N_UNWGT; RUN;
  DATA __U5__.MORT1; SET __U5__.MORT1(KEEP=W_BYVAR N_WGT N_UNWGT); MORTRATE=1; RUN;

  PROC MEANS DATA=__U5__.N_ALL NOPRINT; VAR NWGT UNWGT; BY W_BYVAR;
  WHERE AGEEXP IN (1,2,3,4); OUTPUT OUT=__U5__.MORT2 MIN=N_WGT N_UNWGT; RUN;
  DATA __U5__.MORT2; SET __U5__.MORT2(KEEP=W_BYVAR N_WGT N_UNWGT); MORTRATE=2; RUN;

  PROC MEANS DATA=__U5__.N_ALL NOPRINT; VAR NWGT UNWGT; BY W_BYVAR;
  WHERE AGEEXP IN (1,2,3,4); OUTPUT OUT=__U5__.MORT3 MIN=N_WGT N_UNWGT; RUN;
  DATA __U5__.MORT3; SET __U5__.MORT3(KEEP=W_BYVAR N_WGT N_UNWGT); MORTRATE=3; RUN;


  PROC MEANS DATA=__U5__.N_ALL NOPRINT; VAR NWGT UNWGT; BY W_BYVAR;
  WHERE AGEEXP IN (5,6,7,8); OUTPUT OUT=__U5__.MORT4 MIN=N_WGT N_UNWGT; RUN;
  DATA __U5__.MORT4; SET __U5__.MORT4(KEEP=W_BYVAR N_WGT N_UNWGT); MORTRATE=4; RUN;

  PROC MEANS DATA=__U5__.N_ALL NOPRINT; VAR NWGT UNWGT; BY W_BYVAR;
  OUTPUT OUT=__U5__.MORT5 MIN=N_WGT N_UNWGT; RUN;
  DATA __U5__.MORT5; SET __U5__.MORT5(KEEP=W_BYVAR N_WGT N_UNWGT); MORTRATE=5; RUN;

  DATA __U5__.N_ALL; SET __U5__.MORT1 __U5__.MORT2 __U5__.MORT3 __U5__.MORT4 __U5__.MORT5; RUN;

  PROC SORT DATA=__U5__.N_ALL;  BY W_BYVAR MORTRATE; RUN;
  PROC SORT DATA=__U5__.TEMP0; BY W_BYVAR MORTRATE; RUN;

  DATA __U5__.TEMP0; MERGE __U5__.TEMP0 __U5__.N_ALL; BY W_BYVAR MORTRATE; RUN;

  /*** combining all info ****/

  PROC SORT DATA=__U5__.RESULT; BY COLPER W_BYVAR MORTRATE; RUN;
  PROC SORT DATA=__U5__.TEMP0;  BY COLPER W_BYVAR MORTRATE; RUN;
  %if %symexist(debug) %then %do; proc print data=__u5__.result;run; %end;
  %if %length(&_count_) > 0 %then
  %do;
      %let title8 = &title8 &outlib..counts_&_count_ ;
  %end;

  PROC FORMAT library=&outlib;
  VALUE MORTF 1='NEONATAL'   2='POSTNEONATAL'    3='INFANT'
  4='CHILD'      5='UNDER 5';
  RUN;
  PROC FORMAT;
    VALUE MORTF 1='NEONATAL'   2='POSTNEONATAL'    3='INFANT'
    4='CHILD'      5='UNDER 5';
  RUN;

  /**** retrieve the format associated to the by variable ****/
  %IF &BYVAR ^= %THEN
  %DO;
    %local fmt;%let fmt=;
    data _null_;
    set &data(obs=1);
      fmt = vformat(&byvar);
      call symput("fmt",fmt);
    run;
  %END;

  DATA WORK.ALL; MERGE __U5__.TEMP0 __U5__.RESULT;
  LENGTH VARIABLE $ 8;
  BY COLPER W_BYVAR MORTRATE;
  VARIANCE=(SUM_RR2 - 2*SUMCOUNT*RATE + NCLUSTER*RATE*RATE)*(NCLUSTER-1)/NCLUSTER;
  STDERROR=sqrt(VARIANCE);
  IF RATE^=0 THEN RELERROR = STDERROR/RATE; ELSE RELERROR=.;
  LOWER =RATE -2*STDERROR;  UPPER= RATE +2*STDERROR;
  IF LOWER<0 THEN LOWER=0;
  TYPE='Rate';
  VAR_SRS=RATE*(1000-RATE)/(N_UNWGT*1000000);
  IF VAR_SRS^=0 THEN DEFT=SQRT(VARIANCE/VAR_SRS)/1000; ELSE DEFT=.;
  SRS=SQRT(VAR_SRS)*1000;
  %if %symexist(debug) %then put w_byvar= sum_rr2= sumcount= rate= ncluster= variance= STDERROR= relerror= ;;
  IF MORTRATE=1 THEN VARIABLE='NEOMORT';
  IF MORTRATE=2 THEN VARIABLE='PNMORT ';
  IF MORTRATE=3 THEN VARIABLE='INMORT ';
  IF MORTRATE=4 THEN VARIABLE='CMORT  ';
  IF MORTRATE=5 THEN VARIABLE='U5MORT ';
  FORMAT MORTRATE MORTF. N_UNWGT N_WGT 8.0;
  FORMAT RATE STDERROR RELERROR LOWER UPPER SRS DEFT 8.3;

  %IF &BYVAR^= %THEN
  %DO;
    rename w_byvar = &byvar;
    format w_byvar &fmt;
  %END;
    *KEEP w_byvar VARIABLE MORTRATE RATE STDERROR RELERROR LOWER UPPER DEFT;
    TIME = DATETIME();
    DROP colper percent sum_rr2 sumcount type var_srs srs ran;
  RUN;
  %local this that;
  %do i = 1 %to 8;
    %let this = &&title&i;
    %let that = &&this;
    footnote&i "&that";
  %end;

  OPTIONS LS=120 NODATE NONUMBER FORMDLIM=' ';
  /* get entire sample N */
  %local total_count;%let total_count=;
  proc means data=__u5__.gross_count noprint;
    var count_per_bygroup;
    output out=__u5__.sumcount sum=total_count;
  run;
  data _null_;
  set __u5__.sumcount;
    call symput("total_count",strip(put(total_count,9.)));
  run;

  %IF &BYVAR=  %THEN
  %DO;
    PROC PRINT DATA=WORK.ALL NOOBS HEADING=HORIZONTAL WIDTH=MINIMUM;
    VAR VARIABLE MORTRATE RATE STDERROR /*N_UNWGT N_WGT  DEFT*/ RELERROR LOWER UPPER;
    WHERE W_BYVAR=.;
    TITLE1 ' SAMPLING ERRORS ';
    TITLE3 " ENTIRE SAMPLE / N = &total_count";
    RUN;
  %END;

  %IF &BYVAR^= %THEN
  %DO;
    PROC SORT DATA=WORK.ALL; BY &BYVAR; RUN;
    proc sort data=__u5__.gross_count(rename=(w_byvar=&byvar));by &byvar;run;
    data WORK.ALLfmt(index=(g_var));
    merge WORK.ALL __u5__.gross_count;
    by &byvar;
      attrib g_var label="Grouping variable" format = $32.;
      g_var = strip(put(&byvar,&fmt.)) || " N = " || strip(put(count_per_bygroup,8.));
    run;

    proc print data=WORK.ALL;
    where &byvar = .;
    TITLE ' SAMPLING ERRORS ';
    TITLE3 " ENTIRE SAMPLE N = &total_count";
    VAR VARIABLE MORTRATE  RATE STDERROR /*N_UNWGT N_WGT  DEFT*/ RELERROR LOWER UPPER;
    run;
    PROC PRINT DATA=WORK.ALLfmt NOOBS HEADING=HORIZONTAL WIDTH=MINIMUM;
    where NOT missing(&byvar);
    VAR VARIABLE MORTRATE  RATE STDERROR /*N_UNWGT N_WGT  DEFT*/ RELERROR LOWER UPPER;
    BY g_var; TITLE ' SAMPLING ERRORS ';
    RUN;
  %END;
  data &outlib..DHS_U5M_&_count_;
  set work.all;
  run;

  %put &title8;
  %logline;

%mainexit:
  %if %symexist(debug) = 0 AND #&dont_delete=#okay_to_delete %then
  %do;
    proc datasets library=__U5__ nolist kill;run;quit;
  %end;
  footnote;title;
  options &note_option;
%MEND MORT_DHS_DGHE;


/*
  %macro check_create_date_vars(data=ds=_LAST_, invar=, return_var=,future_years=0, fractional=0);
    add to dataset a variable = return_var in ds
  - returns CMC dates from various date configurations
  - returns missing if 1900 <= year <= thisyear + optional future years
  - returns fractional CMC if fractional = 1 and/or addfraction = 1
    %check_create_date_vars (
      data = dataset of interest or _LAST_
      invar = CMC date
              month year (two variables) (if month out of range then returns uniform random month)
              SAS sasdate (one modifier - SAS - sasdate variable)
              day month year (three variables)
      return_var = name of return variable (NOTE: will overwrite a variable of the same name in the dataset)
      [future_years] = number of future years to add to this year (optional)
      [fractional] = 1 returns an added fractional day ( uniform random if invar is not ('day month year' or 'SAS sasdate'))
                   = 2 returns CMC with +- (.5 * random uniform - smooths)
                      - rounded to .01
                      NOTE: 'day month year' always produces added fractional CMC dates

  SSA 11/15/2011
  TODO strictly add fuzz or +- .5 fuzz - parameterize?
 */
%macro clean_log(onoroff);
  %if #&onoroff = #ON %then
  %do;
    filename bucket DUMMY;
    proc printto log = bucket;
    run;
  %end;
  %else
  %do;
    proc printto;
    run;
  %end;
%mend;

%macro check_create_date_vars(data=_LAST_, invar=, return_var=,future_years=0,fractional=0);

  %local do_sas;
  %let do_sas = %sysfunc(upcase(%sysfunc(strip(%scan(&invar,1)))));
  %if #&do_sas = #SAS %then %let invar = %scan(&invar,2);

  %check_ds_vars(&data,,&invar,1);

  %if %length(&file_errmsg) > 0 %then %goto exit;
  %if %length(&var_nonnum_errmsg) > 0 %then %goto exit;

  %if %length(&future_years) = 0 %then %let future_years = 0;
  %local numwords;
  %global date_errmsg;

  %if %length(&return_var) = 0 %then
  %do;
    %let date_errmsg = No return variable name found.;
    %put &date_errmsg;
    %goto exit;
  %end;
  %global &return_var;
  %if %length(&invar) > 0 %then %let numwords = %sysfunc(countw(&invar));
  %else
  %do;
    %let date_errmsg = No date variable found.;
    %put &date_errmsg;
    %goto exit;
  %end;


  %local addme;
  %if &fractional = 1 %then
  %do;
    %let addme = round(ranuni(12345678),.01);
    %put Processing added fractional CMC dates;
  %end;
  %else %if &fractional = 2 %then
  %do;
    %let addme = round((0.5 - ranuni(12345678)),.01);
    %put Processing added fractional CMC dates;
  %end;
  %else %let addme = 0;

  %if &numwords = 1 %then
  %do;
    %if #&do_sas = #SAS %then
    %do;
      %let sasdate  = &invar;
      %put Processing &sasdate as SASDATE;
      data &data;
      set &data;
        __sasdate__ = &sasdate;
        __addme__ = 0;
        if NOT (1900 <= year(__sasdate__) <= year(date()) + &future_years) then
        do;
          format __sasdate__ date9.;
          put "NOTE: Year not between 1900 and current year + &future_years, using missing:  " _N_= __sasdate__=;
          __sasdate__ = .;
        end;
        else
        do;
          if NOT missing(__sasdate__) then
          do;
            %if &fractional = 1 %then
            %do;
              __addme__ = round((day(&sasdate)/30.43),.01);
            %end;
            &return_var = ((year(&sasdate) - 1900) * 12) + month(&sasdate) + __addme__;
          end;
        end;
        drop __sasdate__ __addme__;
      run;
      %goto exit;
    %end;
    %else
    %do;
      %put Processing &invar as CMC date;
      data &data;
      set &data;
        &return_var = &invar + &addme;
      run;
    %end;
    %goto exit;
  %end;
  %else %if &numwords = 2 %then
  %do;
    %local month year sasdate;
    %let month = %scan(&invar,1);
    %let year  = %scan(&invar,2);
    %put Processing &invar as month year;
    data &data;
    set &data;
      if NOT( 1 <= &month <= 12) then
      do;
        ___month___ = int(ranuni(123456789) * 12) + 1;
        put "NOTE: Month out of range using random 1 - 12: " _N_= &month=;
      end;
      else ___month___ = &month;
      if NOT (1900 <= &year <= year(date()) + &future_years) then
      do;
        put "NOTE: Year not between 1900 and current year + &future_years, using missing:  " _N_= &year=;
        ___year___ = .;
        ___month___ = .;
      end;
      else
      do;
        &return_var = ((&year - 1900) * 12) + ___month___ + &addme;
      end;
      drop ___year___ ___month___;
    run;
    %goto exit;
  %end;
  %else %if &numwords = 3 %then
  %do;
    %put Processing &invar as day month year;
    %let &return_var = day month year;
    %local month year;
    %let day   = %scan(&invar,1);
    %let month = %scan(&invar,2);
    %let year  = %scan(&invar,3);

    data &data;
    set &data;

      if NOT( 1 <= &day <= 31) then
      do;
        ___day___ = int(ranuni(123456789) * 30.42) + 1;
        put "NOTE: Day out of range using random 1 - 30.42: " _N_= &month=;
      end;
      else ___day___ = &day;
      if NOT( 1 <= &month <= 12) then
      do;
        ___month___ = int(ranuni(123456789) * 12) + 1;
        put "NOTE: Month out of range using random 1 - 12: " _N_= &month=;
      end;
      else ___month___ = &month;
      if NOT (1900 <= &year <= year(date()) + &future_years) then
      do;
        put "NOTE: Year not between 1900 and current year + &future_years, using missing:  " _N_= &year=;
        ___year___ = .;
        ___month___ = .;
        ___day___ = .;
      end;
      else
      do;
        &return_var = ((&year - 1900) * 12) + ___month___ + (___day___/30.42);
      end;
      drop ___year___ ___month___ ___day___;
    run;

  %end;
 %exit:

%mend;

/*
  macro check_ds_vars
  Check existence of a dataset
  USAGE check_ds_vars(dataset_name, list of variables, list of numeric variables,printerror);

    dataset_name - one or two part dataset name
    list of variables - variables to check the existence of
    list of numeric variables - variables to check to make sure they're numeric (and existing)
    printerror - 1 will cause macro to print errors in log - anything else will not

    This macro returns 3 global macro variables.
    file_errmsg - File error message if dataset cannot be found
    var_missing_errmsg - list of variables not found
    var_nonum_errmsg   - list of variables that are not numeric

    These macro variables will overwrite any macro variables of the same name.
*/


%macro check_ds_vars(file_name,varlist,nvarlist,printerror);
  %local rc notesoption;
  %let notesoption = %sysfunc(getoption(notes));
  options nonotes;
  %global file_errmsg var_missing_errmsg var_nonnum_errmsg;
  %let file_errmsg=;
  %let var_missing_errmsg=;
  %let var_nonnum_errmsg=;

  %if %length(&file_name) = 0 %then %let file_name = Not specified!;
  %let rc = %sysfunc(exist(&file_name));
  %if  &rc >= 1 %then
  %do;
    proc contents data=&file_name noprint out=__contents;
    run;
    data _null_;
    set __contents end = last;
      format outline1 outline2 $32000.;
      retain %if %length(&varlist) > 0 %then
                v1 - v%sysfunc(countw(&varlist));
             %if %length(&nvarlist) > 0 %then
                n1 - n%sysfunc(countw(&nvarlist));
      ;
      %if %length(&varlist) > 0 %then
      %do i = 1 %to %sysfunc(countw(&varlist));
        if upcase("%scan(&varlist,&i)") = upcase(name) then v&i = type;
      %end;
      %if %length(&nvarlist) > 0 %then
      %do i = 1 %to %sysfunc(countw(&nvarlist));
        if upcase("%scan(&nvarlist,&i)") = upcase(name) then n&i = type;
      %end;

      if last then
      do;
        %if %length(&varlist) > 0 %then
        %do i = 1 %to %sysfunc(countw(&varlist));
          if missing(v&i) then outline1 = strip(outline1) || " " || "%scan(&varlist,&i)";
        %end;
        %if %length(&nvarlist) > 0 %then
        %do i = 1 %to %sysfunc(countw(&nvarlist));
          if n&i = 2 then outline2 = strip(outline2) || " " || "%scan(&nvarlist,&i)";
          else if missing(n&i) then outline1 = strip(outline1) || " " || "%scan(&nvarlist,&i)";
        %end;

        call symput("var_missing_errmsg",strip(outline1));
        call symput("var_nonnum_errmsg" ,strip(outline2));
      end;
    run;
  %end;
  %else %let file_errmsg = Dataset &file_name not found;
  %if #&printerror = #1 %then
  %do;
    %if %length(&file_errmsg)        > 0 %then %put ERROR: Dataset not found = &file_errmsg;
    %if %length(&var_missing_errmsg) > 0 %then %put ERROR: Missing variables = &var_missing_errmsg;
    %if %length(&var_nonnum_errmsg)  > 0 %then %put ERROR: Non-numeric variables = &var_nonnum_errmsg;
  %end;
  options &notesoption;
%mend;
%macro logline();
  %put;%put ********************************************************************************************;%put;
%mend;
